#include "matrix.h"
#include <algorithm>
#include <sstream>

matrix_t::matrix_t(size_t rows, size_t cols)
    : _rows{rows}, _cols{cols}
{
    data = new ration_t[rows * (cols + 1)];
}

matrix_t::~matrix_t()
{
    delete[] data;
}

ration_t &matrix_t::operator()(size_t i, size_t j)
{
    return operator[](__get_pos(i, j));
}
ration_t &matrix_t::operator[](size_t index)
{
    return data[index];
}

void matrix_t::swap_rows(size_t r1, size_t r2)
{
    for (int i = 0; i < _cols; ++i)
    {
        std::swap(data[__get_pos(r1, i)], data[__get_pos(r2, i)]);
    }
}
void matrix_t::swap_cols(size_t c1, size_t c2)
{
    for (int i = 0; i < _rows; ++i)
    {
        std::swap(data[__get_pos(i, c1)], data[__get_pos(i, c2)]);
    }
}
void matrix_t::add_row(size_t r1, size_t r2, const ration_t &value)
{
    for (int j = 0; j < _cols; ++j)
    {
        data[__get_pos(r1, j)] += data[__get_pos(r2, j)] * value;
    }
}
void matrix_t::add_col(size_t c1, size_t c2, const ration_t &value)
{
    for (int i = 0; i < _rows; ++i)
    {
        data[__get_pos(i, c1)] += data[__get_pos(i, c2)] * value;
    }
}

void matrix_t::scale_row(size_t r, const ration_t &scale)
{
    for (int j = 0; j < _cols; ++j)
    {
        data[__get_pos(r, j)] *= scale;
    }
}
void matrix_t::scale_col(size_t c, const ration_t &scale)
{
    for (int i = 0; i < _rows; ++i)
    {
        data[__get_pos(i, c)] *= scale;
    }
}

size_t matrix_t::get_rows()
{
    return _rows;
}
size_t matrix_t::get_cols()
{
    return _cols;
}

std::string matrix_t::to_latex()
{
    std::stringstream ss;
    ss << R"(\begin{bmatrix})";
    for (int i = 0; i < _rows; ++i)
    {
        for (int j = 0; j < _cols - 1; ++j)
            ss << data[__get_pos(i, j)].to_latex() << '&';
        ss << data[__get_pos(i, _cols - 1)].to_latex() << R"(\\)";
    }
    ss << R"(\end{bmatrix})";
    return ss.str();
}

istream &operator>>(istream &in, matrix_t &me)
{
    for (int i = 0; i < me.get_rows(); ++i)
        for (int j = 0; j < me.get_cols(); ++j)
            in >> me(i, j);
    return in;
}

ostream &operator<<(ostream &out, matrix_t &me)
{
    for (int i = 0; i < me.get_rows(); ++i)
    {
        for (int j = 0; j < me.get_cols(); ++j)
            out << me(i, j) << ' ';
        out << std::endl;
    }
    return out;
}

size_t matrix_t::__get_pos(size_t i, size_t j)
{
    return j * _cols + i;
}
